package cz.cvut.fit.crhonjar.mi.paa.thames.manager;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;

import cz.cvut.fit.crhonjar.mi.paa.thames.Configuration;
import cz.cvut.fit.crhonjar.mi.paa.thames.Item;
import cz.cvut.fit.crhonjar.mi.paa.thames.exception.ThamesException;
import cz.cvut.fit.crhonjar.mi.paa.thames.solver.Solver;

/**
 * 
 * @author Jarec
 * 
 */
public class ProblemManager {

	private static Integer capacityReader(final String line) {
		final int indexOfSecondSpace = line.indexOf(' ', line.indexOf(' ') + 1);
		final int indexOfThirdSpace = line.indexOf(' ', indexOfSecondSpace + 1);
		final String capacityText = line.substring(indexOfSecondSpace + 1,
				indexOfThirdSpace);
		return new Integer(capacityText);
	}

	private static Integer idReader(final String line) {
		final int indexOfSpace = line.indexOf(' ');
		final String idText = line.substring(0, indexOfSpace);
		return new Integer(idText);
	}

	private static List<Item> itemReader(final String line) {
		final List<Item> items = new ArrayList<Item>();
		final Integer size = ProblemManager.sizeReader(line);
		final int indexOfSecondSpace = line.indexOf(' ', line.indexOf(' ') + 1);
		int indexOfSpace = line.indexOf(' ', indexOfSecondSpace + 1);
		for (int i = 0; i < size; i++) {
			final int indexOfNextSpace = line.indexOf(' ', indexOfSpace + 1);
			final Integer weight = new Integer(line.substring(indexOfSpace + 1,
					indexOfNextSpace));
			final int indexOfFollowingSpace = line.indexOf(' ',
					indexOfNextSpace + 1);
			Integer price;
			if (indexOfFollowingSpace == -1) {
				price = new Integer(line.substring(indexOfNextSpace + 1));
			} else {
				price = new Integer(line.substring(indexOfNextSpace + 1,
						indexOfFollowingSpace));
			}
			items.add(new Item(weight, price, i));
			indexOfSpace = indexOfFollowingSpace;
		}
		return items;
	}

	private static Integer sizeReader(final String line) {
		final int indexOfSpace = line.indexOf(' ');
		final int indexOfSecondSpace = line.indexOf(' ', indexOfSpace + 1);
		final String sizeText = line.substring(indexOfSpace + 1,
				indexOfSecondSpace);
		return new Integer(sizeText);
	}

	private final Integer bagCapacity;
	private final Integer id;

	private final List<Item> items;

	private Configuration lastResult;

	private Solver solver;

	private BigDecimal solvingTime;

	/**
	 * @param line
	 */
	public ProblemManager(final String line) {
		if ((line == null) || (line.length() == 0)) {
			throw new IllegalArgumentException("Not valid instance line given!");
		}
		this.items = ProblemManager.itemReader(line);
		this.id = ProblemManager.idReader(line);
		this.bagCapacity = ProblemManager.capacityReader(line);
		this.solvingTime = null;

	}

	/**
	 * @param solver
	 */
	public void accept(final Solver solver) {
		if (solver == null) {
			throw new IllegalArgumentException(
					"Cannot solve problem with NULL solver!");
		}
		this.solver = solver;
		solver.initiate(this.items, this.bagCapacity);
	}

	/**
	 * @return the bagCapacity
	 */
	public Integer getBagCapacity() {
		return this.bagCapacity;
	}

	/**
	 * @return the id
	 */
	public Integer getId() {
		return this.id;
	}

	/**
	 * @return the items
	 */
	public List<Item> getItems() {
		return this.items;
	}

	/**
	 * @return
	 */
	public Solver getSolver() {
		return this.solver;
	}

	/**
	 * @return the solvingTime
	 * @throws IllegalAccessException
	 */
	public BigDecimal getSolvingTime() throws IllegalAccessException {
		if (this.solvingTime == null) {
			throw new IllegalAccessException(
					"Solving time is not available! Did you run solve()?");
		}
		return this.solvingTime;
	}

	/**
	 * @param printItems
	 * @throws IllegalAccessException
	 */
	public void printLastResult(final Boolean printItems)
			throws IllegalAccessException {
		if (this.solver == null) {
			throw new IllegalAccessException(
					"Solver must be initiated before last result can be printed!");
		}
		if (this.lastResult == null) {
			throw new IllegalAccessException(
					"Last result does not exist yet. Didnt you forget to call solve()?");
		}
		if (this.solvingTime == null) {
			this.solvingTime = BigDecimal.ZERO;
		}
		System.out.print(this.solver.getName() + ":\n");
		System.out.println("ID: " + this.getId() + " capacity: "
				+ this.getBagCapacity() + " price: "
				+ this.lastResult.getPrice() + " weight: "
				+ this.lastResult.getWeight() + " took: "
				+ this.getSolvingTime() + "ms");
		if (printItems) {
			for (int i = 0; i < this.lastResult.getItems().size(); i++) {
				if (this.lastResult.getPresence().get(i)) {
					System.out
							.println("\t" + this.lastResult.getItems().get(i));
				}
			}
		}
	}

	/**
	 * @return
	 * @throws ThamesException
	 * @throws CloneNotSupportedException
	 */
	public Configuration solve() throws ThamesException,
			CloneNotSupportedException {
		final BigDecimal start = new BigDecimal(System.nanoTime())
				.divide(new BigDecimal(1000000));
		this.lastResult = this.solver.solve();
		final BigDecimal stop = new BigDecimal(System.nanoTime())
				.divide(new BigDecimal(1000000));
		this.solvingTime = stop.subtract(start).setScale(3,
				RoundingMode.HALF_UP);
		return this.lastResult;
	}

}
